package com.example.skymallseckillproductapi.api;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.skymallseckillproductapi.service.OrderFeignService;
import com.mysql.cj.x.protobuf.MysqlxCrud;
import com.situ.model.Order;
import com.situ.model.OrderItem;
import com.situ.shop.model.DTO.SecKillProductWithProductInfo;
import com.situ.shop.model.SecKillProduct;
import com.situ.shop.model.SecKillStatus;
import com.situ.shop.model.search.SecKillProductSearchBean;
import com.situ.shop.service.SecKillProductService;
import com.situ.shop.service.UploadService;
import com.situ.utils.JsonResult;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;

@RestController
@RequestMapping(value = "/api/v1/secKillProducts", produces = MediaType.APPLICATION_JSON_VALUE)
public class SecKillProductApi {


    @Value("${jwt.secret}")
    private String jwtSecret;

    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    private SecKillProductService secKillProductService;
    private UploadService uploadService;
    private Snowflake snowflake;
    private RocketMQTemplate rocketMQTemplate;
    private OrderFeignService orderFeignService;
    @Autowired
    public void setOrderFeignService(OrderFeignService orderFeignService) {
        this.orderFeignService = orderFeignService;
    }

    @Autowired
    public void setRocketMQTemplate(RocketMQTemplate rocketMQTemplate) {
        this.rocketMQTemplate = rocketMQTemplate;
    }

    //保证分布式下的id不冲突
    @Autowired
    public void setSnowflake(Snowflake snowflake) {
        this.snowflake = snowflake;
    }

    @Autowired
    public void setUploadService(UploadService uploadService) {
        this.uploadService = uploadService;
    }

    @Autowired
    public void setSecKillProductService(SecKillProductService secKillProductService) {
        this.secKillProductService = secKillProductService;
    }

    // 秒杀接口
    // userId:用户id，id:秒杀商品id，quantity:数量
    @PostMapping("/seckill/{id}")
    public ResponseEntity<JsonResult<?>> seckill(@PathVariable Integer id, HttpServletRequest request) {
        if (id == null) {
            return ResponseEntity.ok(JsonResult.fail("商品ID不能为空"));
        }
        //1.查询秒杀商品
        SecKillProductWithProductInfo secKillProduct = null;
        ResponseEntity<JsonResult<SecKillProductWithProductInfo>> re = findByIdWithProductInfo(id);
        JsonResult<SecKillProductWithProductInfo> jr = re.getBody();
        if (jr != null && jr.isSuccess()) {
            secKillProduct = jr.getData();//秒杀商品
        }

        if (secKillProduct == null) {
            return ResponseEntity.ok(JsonResult.fail("商品不存在"));
        }
        //2.获取用户  从jwt token中获取
        // 从JWT token中获取用户ID

        String authHeader = request.getHeader("Authorization");
        System.out.println("Authorization:"+authHeader);

        if (!StringUtils.hasText(authHeader)) {
            authHeader = request.getParameter("Authorization");
        }


        String jwt = null;
        Integer userId = null;
        if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
            jwt = authHeader.substring(7);
        } else {
            jwt = authHeader; // 兼容没有 "Bearer " 的情况
        }
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(jwtSecret)).build();
            try {
                DecodedJWT dj = verifier.verify(jwt);
                 userId = dj.getClaim("userId").asInt();



                System.out.println("用户ID:"+userId);
            } catch (JWTVerificationException e) {
                return ResponseEntity.ok(JsonResult.fail("用户身份验证失败"+e.getMessage()));
            }




        //3.判断是否可以创建订单：一千万只有10个个人创建订单,在这里过滤大量请求。执行lua脚本
        //3.1判断会员是否买过该商品了
        //3.2判断当前秒杀商品是否已结束
        //3.3判断当前秒杀商品是否仍有库存
        //3.4扣减库存,更新库存

        //调用lua脚本,只要导入了redis依赖就可以使用
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        //设置脚本执行返回的结果类型
        redisScript.setResultType(Long.class);
        //设置脚本位置
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("seckill.lua")));
        //执行lua脚本，传参数，返回结果
        long result = redisTemplate.execute(redisScript, List.of(id.toString()), userId);
        if (result == -100) {
            return ResponseEntity.ok(JsonResult.fail("您已秒杀过此商品"));
        } else if (result == -200) {
            return ResponseEntity.ok(JsonResult.fail("此商品已结束秒杀"));
        } else if (result == -300) {
            return ResponseEntity.ok(JsonResult.fail("库存已不足"));
        }

        //4.创建订单
        Order order = new Order();
        order.setUserId(userId);
        //秒杀订单号
        String seckillNo = snowflake.nextIdStr();
        order.setSeckillNo(seckillNo);
        OrderItem orderItem = new OrderItem();
        orderItem.setQuantity(1);
        orderItem.setProductPrice(secKillProduct.getSeckillPrice());
        orderItem.setProductName(secKillProduct.getName());
        orderItem.setProductId(secKillProduct.getProductId());
        order.setOrderItems(List.of(orderItem));

        //5.保存订单:使用消息队列异步保存订单
        this.rocketMQTemplate.asyncSend("skymall-orders", order, new SendCallback() {
           //消息发送成功,不做处理,等待消费者消费
            @Override
            public void onSuccess(SendResult sendResult) {
            //do nothing....
            }
            //消息发送失败,轮询重试,循环定时每隔时间询问一下
            @Override
            public void onException(Throwable throwable) {
                    //秒杀订单是否成功创建的标记
                    SecKillProductApi.this.redisTemplate.opsForValue().set("seckill-order:" + seckillNo, false, Duration.ofMinutes(5));
            }
        });

        return ResponseEntity.ok(JsonResult.success(seckillNo));

    }
    //判断秒杀订单是否已经成功创建
    @GetMapping("/check_order_created")
     public ResponseEntity<JsonResult<?>> checkIfOrderCreated(String seckillNo){

        Boolean success=(Boolean)this.redisTemplate.opsForValue().get("seckill-order:" + seckillNo);
        //避免空指针异常
        if(Boolean.FALSE.equals(success)){
            return ResponseEntity.ok(JsonResult.fail("订单创建失败"));
        }

       ResponseEntity<JsonResult<Order>>re= this.orderFeignService.findBySeckillNo(seckillNo);
       JsonResult <Order>jr=re.getBody();
       if(jr!=null&&jr.isSuccess()){
           return ResponseEntity.ok(JsonResult.success(jr.getData().getId()));
       }
       //这里null的原因是为了让前端 在resp.msg时轮询等待
        return ResponseEntity.ok(new JsonResult<>(404, false, null, null));
     }


    // 查询秒杀状态
    @GetMapping("/{id}/status")
    public ResponseEntity<JsonResult<?>> checkSecKillStatus(@PathVariable Integer id) {
        SecKillStatus status = this.secKillProductService.checkSecKillStatus(id);
        return ResponseEntity.ok(JsonResult.success(status));
    }

    //查询所有
    @GetMapping
    public ResponseEntity<JsonResult<?>> findAll(@RequestParam(defaultValue = "1") Integer pageNo,
                                                 @RequestParam(defaultValue = "10") Integer pageSize,
                                                 SecKillProductSearchBean spsb) {
        Page<SecKillProduct> page = new Page<>(pageNo, pageSize);
        page = this.secKillProductService.findAll(page, spsb);
        return ResponseEntity.ok(JsonResult.success(page));
    }

    /**
     * @param id 秒杀商品id
     * @return 操作结果
     */
    @PutMapping("/offShelves/{id}")
    public ResponseEntity<?> offShelvesSecKillProduct(@PathVariable Long id) {
        try {
            // 调用服务层下架商品
            secKillProductService.offShelves(id);
            return ResponseEntity.ok().body("下架成功");
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("下架失败: " + e.getMessage());
        }
    }


    //根据id查询秒杀商品
    //自定义响应内容 蕴含代码侵入
    //@SentinelResource(value ="secKillProduct-api-findById",blockHandler = "blockFindById",fallback = "fallbackFindById")
    @GetMapping("/id/{id}")
    public ResponseEntity<JsonResult<SecKillProduct>> findById(@PathVariable Integer id) {
        SecKillProduct secKillProduct = secKillProductService.findById(id);
        //模拟异常
//                Random random=new Random();
//                int i=random.nextInt(10);
//                if(i<5){
//                        throw new RuntimeException("出现异常");
//                }
        //以上为模拟异常

        if (secKillProduct == null) {
            return ResponseEntity.ok(new JsonResult<>(0, false, "未找到该记录", null));
        }
        return ResponseEntity.ok(JsonResult.success(secKillProduct));
    }


    //(降级)当出现熔断和限流的时候  优先级比配置类的高
//        public ResponseEntity<JsonResult<?>> blockFindById(Integer id, BlockException blockException){
//                if(blockException instanceof FlowException){
//                        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(JsonResult.fail("服务器繁忙0--限流"));
//                }else if(blockException instanceof DegradeException){
//                        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(JsonResult.fail("服务器繁忙0--熔断"));
//                }
//                return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(JsonResult.fail("服务器繁忙1--限流或熔断"));
//        }
//       既不是熔断也不是限流,普通业务异常
//        public ResponseEntity<JsonResult<?>> fallbackFindById(Integer id, Throwable throwable){
//                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(JsonResult.fail("服务器繁忙2---普通业务异常"));
//        }


    //        根据id查出该秒杀商品的全部信息包括图片等等
    @GetMapping("/id/{id}/withProductInfo")
    @SentinelResource(value = "secKillProduct-api-findByIdWithInfo", blockHandler = "blockFindById", fallback = "fallbackFindById")
    public ResponseEntity<JsonResult<SecKillProductWithProductInfo>> findByIdWithProductInfo(@PathVariable Integer id) {
        //模拟异常
//                Random random=new Random();
//                int i=random.nextInt(10);
//                if(i<5){
//                        throw new RuntimeException("出现异常");
//                }
        //以上为模拟异常
        SecKillProductWithProductInfo secKillProductWithProductInfo = secKillProductService.selectByIdWithProductInfo(id);
        if (secKillProductWithProductInfo == null) {
            return ResponseEntity.ok(new JsonResult<>(0, false, "未找到该记录", null));
        }
        return ResponseEntity.ok(JsonResult.success(secKillProductWithProductInfo));
    }

    //查出所有秒杀商品带全部信息
    @GetMapping("/withProductInfo")
    public ResponseEntity<JsonResult<?>> selectAllWithProductInfo() {
        List<SecKillProductWithProductInfo> list = this.secKillProductService.selectAllWithProductInfo();
        return ResponseEntity.ok(JsonResult.success(list));
    }

    //根据查询条件查出所有秒杀商品带全部信息
    @GetMapping("/withProductInfo/condition")
    public ResponseEntity<JsonResult<?>> selectWithProductInfoByCondition(SecKillProductSearchBean condition,
                                                                          @RequestParam(defaultValue = "1") Integer pageNo,
                                                                          @RequestParam(defaultValue = "10") Integer pageSize) {
        //创建分页对象
        Page<SecKillProductWithProductInfo> page = new Page<>(pageNo, pageSize);
        //获取符合条件的数据
        List<SecKillProductWithProductInfo> list = this.secKillProductService.selectWithProductInfoByCondition(condition);

        //手动分页
        int total = list.size();
        int fromIndex = (pageNo - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, total);

        if (fromIndex <= total) {
            List<SecKillProductWithProductInfo> pageList = list.subList(fromIndex, toIndex);
            page.setRecords(pageList);
            page.setTotal(total);
            page.setPages((total + pageSize - 1) / pageSize); // 正确的总页数计算
        }
        return ResponseEntity.ok(JsonResult.success(page));

    }


    //保存
    @PostMapping
    public ResponseEntity<JsonResult<?>> save(@RequestBody SecKillProduct secKillProduct) {
        boolean result = this.secKillProductService.save(secKillProduct);
        if (!result) {
            return ResponseEntity.ok(JsonResult.fail("保存失败"));
        }
        return ResponseEntity.ok(JsonResult.success(null));
    }

    //更新
    @PutMapping
    public ResponseEntity<JsonResult<?>> update(@RequestBody SecKillProduct secKillProduct) {
        boolean result = this.secKillProductService.update(secKillProduct);
        if (!result) {
            return ResponseEntity.ok(JsonResult.fail("修改失败"));
        }
        return ResponseEntity.ok(JsonResult.success(null));
    }

    //        删除
    @DeleteMapping("/ids")
    public ResponseEntity<JsonResult<?>> deleteByIds(@RequestBody Integer[] ids) {
        int result = this.secKillProductService.deleteByIds(Arrays.asList(ids));
        if (result == 0) {
            return ResponseEntity.ok(JsonResult.fail("删除失败"));
        } else {
            return ResponseEntity.ok(JsonResult.success(result));
        }
    }

    //上传图片
    @PostMapping("/avatar")
    public ResponseEntity<JsonResult<?>> uploadMemberAvatar(MultipartFile file) {
        String path = this.uploadService.uploadImage(file, "member_avatar");
        return ResponseEntity.ok(JsonResult.success(path));
    }
}
